References

1 Shiny (tutorial)

1.1 Structure of Shiny App

  • two scripts (in one directory) make up a Shiny project
    • ui.R - controls appearance/all style elements
    • server.R - controls functions
  • runApp() executes the Shiny application
    • runApp(display.mode = 'showcase') = displays the code from ui.R and server.R and highlights what is being executed depending on the inputs
  • Note: "," must be included ONLY INBETWEEN objects/functions on the same level
  • alternatively, a www directory with an index.html file enclosed can be used instead of ui.R
    • Note: output is rendered into HTML elements based on matching their id attribute to an output slot and by specifying the requisite CSS class for the element (in this case either shiny-text-output, shiny-plot-output, or shiny-html-output)
    • it is possible to create highly customized user-interfaces using user-defined HTML/CSS/JavaScript

1.2 ui.R

  • library(shiny) = first line, loads the shiny package
  • shinyUI() = shiny UI wrapper, contains sub-methods to create panels/parts/viewable object
  • titlePanel("title") = specifies a title
  • pageWithSideBar() = creates page with main/side bar division
  • headerPanel("title") = specifies header of the page
  • sidebarLayout() = specifies the sidebar layout
  • sideBarPanel() = specifies parameters/objects in the side bar (on the left)
  • mainPanel() = specifies parameters/objects in the main panel (on the right)
  • for better control over style, use shinyUI(fluidpage()) (tutorial) <– produces responsive web pages
    • fluidRow() = creates row of content with width 12 that can be subdivided into columns
      • column(4, ...) = creates a column of width 4 within the fluid row
      • style = "CSS" = can be used as the last element of the column to specify additional style
  • absolutePanel(top=0, left=0, right=0) = used to produce floating panels on top of the page (documentation)
    • fixed = TRUE = panel will not scroll with page, which means the panel will always stay in the same position as you scroll through the page
    • draggable = TRUE = make panel movable by the user
    • top = 40 / bottom = 50 = position from the top/bottom edge of the browser window
      • top = 0, bottom = 0 = creates panel that spans the entire vertical length of window
    • left = 40 / right = 50 = position from the left/right edge of the browser window
      • top = 0, bottom = 0 = creates panel that spans the entire horizontal length of window
    • height = 30 / width = 40 = specifies the height/width of the panel
    • style = "opacity:0.92; z-index = 100" = makes panel transparent and ensures the panel is always the top-most element
  • content objects/functions
    • Note: more HTML tags can be found here
    • Note: most of the content objects (h1, p, code, etc) can use both double and single quotes to specify values, just be careful to be consistent
    • h1/2/3/4/5/6('heading') = creates heading for the panel
    • p('pargraph') = creates regular text/paragraph
    • a() = hyperlink
    • span() = group inline-elements
    • code('code') = renders code format on the page
    • br() = inserts line break
    • tags$hr() = inserts horizontal line
    • tags$ol()/ tags$ul() = initiates ordered/unordered list
    • div( ... , style = "CSS Code") / span( ... , style = "CSS Code") = used to add additional style to particular parts of the app
      • div should be used for a section/block, span should be used for a specific part/inline
    • withMathJax() = add this element to allow Shiny to process LaTeX
      • inline LaTex must be wrapped like this: \\(LaTeX\\)
      • block equations are still wrapped by: $$LaTeX$$
    • ?builder for more details
  • inputs
    • textInput(inputId = "id", label = "textLabel") = creates a plain text input field
      • inputId = field identifier
      • label = text that appear above/before a field
    • numericInput('HTMLlabel', 'printedLabel', value = 0, min = 0, max = 10, step = 1) = create a number input field with incrementer (up/down arrows)
      • 'HTMLLabel' = name given to the field, not printed, and can be called
      • 'printedLabel' = text that shows up above the input box explaining the field
      • value = default numeric value that the field should take; 0 is an example
      • min = minimum value that can be set in the field (if a smaller value is manually entered, then the value becomes the minimum specified once user clicks away from the field)
      • max = max value that can be set in the field
      • step = increments for the up/down arrows
      • more arguments can be found in ?numericInput
    • checkboxGroupInput("id2", "Checkbox",choices = c("Value 1" = "1", ...), selected = "1", inline = TRUE) = creates a series of checkboxes
      • "id2", "Checkbox" = field identifier/label
      • choices = list of checkboxes and their labels
        • format = "checkboxName" = "fieldIdentifier"
        • Note: fieldIdentifier should generally be different from checkbox to checkbox, so we can properly identify the responses
      • selected = specifies the checkboxes that should be selected by default; uses fieldIndentifier values
      • inline = whether the options should be displayed inline
    • dateInput("fieldID", "fieldLabel") = creates a selectable date field (dropdown calendar/date picker automatically generated)
      • "fieldID" = field identifier
      • "fieldLabel" = text/name displayed above fields
      • more arguments can be found in ?dateInput
    • submitButton("Submit") = creates a submit button that updates the output/calculations only when the user submits the new inputs (default behavior = all changes update reactively/in real time)
    • actionButton(inputId = "goButton", label = "test") = creates a button with the specified label and id
      • output can be specified for when the button is clicked
    • sliderInput("id", "label", value = 70, min = 62, max = 74, 0.05) = creates a slider for input
      • arguments similar to numericInput and more information can be found ?sliderInput
  • outputs
    • Note: every variable called here must have a corresponding method corresponding method from the output element in server.R to render their value
    • textOutput("fieldId", inline = FALSE) = prints the value of the variable/field in text format
      • inline = TRUE = inserts the result inline with the HTML element
      • inline = FALSE = inserts the result in block code format
    • verbatimTextOutput("fieldId") = prints out the value of the specified field defined in server.R
    • plotOutput('fieldId') = plots the output (‘sampleHist’ for example) created from server.R script
    • output$test <- renderText({input$goButton}); isolate(paste(input$t1, input$2))}) = isolate action executes when the button is pressed
      • if (input$goButton == 1){ Conditional statements } = create different behavior depending on the number of times the button is pressed
  • Advanced UI
    • you can mix several other kinds of UI components into your app including tabs, navbars, and sidebars
    • example on tabs:
      • tabsetPanel() = specifies a group of tabs
      • tabPanel() = specifies the contents of an individual tab
  • Interactive Graphics
    • Shiny has the ability to create graphics that a user can interact with.
    • One method is to select multiple data points on a graph is by specifying the brush argument in plotOutput() on the ui.R side, and then using the brushedPoints() function on the server.R side

1.3 ui.R Examples

  • basic example
# basis app with sliders and plot
library(shiny)
shinyUI(fluidPage(
titlePanel("Plot Random Numbers"),
sidebarLayout(
sidebarPanel(
numericInput("numeric", "How Many Random Numbers Should be Plotted?",
value = 1000, min = 1, max = 1000, step = 1),
sliderInput("sliderX", "Pick Minimum and Maximum X Values",
-100, 100, value = c(-50, 50)),
sliderInput("sliderY", "Pick Minimum and Maximum Y Values",
-100, 100, value = c(-50, 50)),
checkboxInput("show_xlab", "Show/Hide X Axis Label", value = TRUE),
checkboxInput("show_ylab", "Show/Hide Y Axis Label", value = TRUE),
checkboxInput("show_title", "Show/Hide Title")
),
mainPanel(
h3("Graph of Random Points"),
plotOutput("plot1")
)
)
))
  • example with tabs
library(shiny)
shinyUI(fluidPage(
titlePanel("Tabs!"),
sidebarLayout(
sidebarPanel(
textInput("box1", "Enter Tab 1 Text:", value = "Tab 1!"),
textInput("box2", "Enter Tab 2 Text:", value = "Tab 2!"),
textInput("box3", "Enter Tab 3 Text:", value = "Tab 3!")
),
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Tab 1", br(), textOutput("out1")),
tabPanel("Tab 2", br(), textOutput("out2")),
tabPanel("Tab 2", br(), textOutput("out3"))
)
)
)
))
  • example with interactive graphics
library(shiny)
shinyUI(fluidPage(
titlePanel("Visualize Many Models"),
sidebarLayout(
sidebarPanel(
h3("Slope"),
textOutput("slopeOut"),
h3("Intercept"),
textOutput("intOut")
),
mainPanel(
plotOutput("plot1", brush = brushOpts(id = "brush1"))
)
)
))
  • below is part of the ui.R code for a project on Shiny
# load shiny package
library(shiny)
# begin shiny UI
shinyUI(navbarPage("Shiny Project",
# create first tab
tabPanel("Documentation",
# load MathJax library so LaTeX can be used for math equations
withMathJax(), h3("Why is the Variance Estimator \\(S^2\\) divided by \\(n-1?\\)"),
# paragraph and bold text
p("The ", strong("sample variance")," can be calculated in ", strong(em("two")),
" different ways:",
"$$S^2 \\mbox{(unbiased)} = \\frac{\\sum_{i=1}^n (X_i - \\bar X)^2}{n-1}
~~~\\mbox{and}~~S^2\\mbox{(biased)}=\\frac{\\sum_{i=1}^n (X_i-\\bar X)^2}{n}$$",
"The unbiased calculation is most often used, as it provides a ",
strong(em("more accurate")), " estimate of population variance"),
# break used to space sections
br(), p("To show this empirically, we simulated the following in the ",
strong("Simulation Experiment"), " tab: "), br(),
# ordered list
tags$ol(
tags$li("Create population by drawing observations from values 1 to 20."),
tags$li("Draw a number of samples of specified size from the population"),
tags$li("Plot difference between sample and true population variance"),
tags$li("Show the effects of sample size vs accuracy of variance estimated")
)),
# second tab
tabPanel("Simulation Experiment",
# fluid row for space holders
fluidRow(
# fluid columns
column(4, div(style = "height: 150px")),
column(4, div(style = "height: 150px")),
column(4, div(style = "height: 150px"))),
# main content
fluidRow(
column(12,h4("We start by generating a population of ",
span(textOutput("population", inline = TRUE),
style = "color: red; font-size: 20px"),
" observations from values 1 to 20:"),
tags$hr(),htmlOutput("popHist"),
# additional style
style = "padding-left: 20px"
)
),
# absolute panel
absolutePanel(
# position attributes
top = 50, left = 0, right =0,
fixed = TRUE,
# panel with predefined background
wellPanel(
fluidRow(
# sliders
column(4, sliderInput("population", "Size of Population:",
min = 100, max = 500, value = 250),
p(strong("Population Variance: "),
textOutput("popVar", inline = TRUE))),
column(4, sliderInput("numSample", "Number of Samples:",
min = 100, max = 500, value = 300),
p(strong("Sample Variance (biased): "),
textOutput("biaVar", inline = TRUE))),
column(4, sliderInput("sampleSize", "Size of Samples:",
min = 2, max = 15, value = 10),
p(strong("Sample Variance (unbiased): "),
textOutput("unbiaVar", inline = TRUE)))),
style = "opacity: 0.92; z-index: 100;"
))
)
))

1.4 server.R

  • preamble/code to set up environment (executed only once)
    • start with library() calls to load packages/data
    • define/initiate variables and relevant default values
      • <<- operator should be used to assign values to variables in the parent environment
      • x <<- x + 1 will define x to be the sum of 1 and the value of x (defined in the parent environment/working environment)
    • any other code that you would like to only run once
  • shinyServer() = initiates the server function
    • function(input, output){} = defines a function that performs actions on the inputs user makes and produces an output object
    • non-reactive statements/code will be executed once for each page refresh/submit
    • reactive functions/code are run repeatedly as values are updated (i.e. render)
      • Note: Shiny only runs what is needed for reactive statements, in other words, the rest of the code is left alone
      • reactive(function) = can be used to wrap functions/expressions to create reactive expressions
        • renderText({x()}) = returns value of x, “()” must be included (syntax)
        • Expressions wrapped by reactive() should be expressions that are subject to change
    • delayed reactivity for long-running calculations
      • in order to prevent reactive expressions from reacting you can use a submit button
        • in ui.R insert a submit button via submitButton("Submit")
        • Note: no changes needed in server.R
  • reactive function example
# start shinyServer
shinyServer(
# specify input/output function
function(input, output) {
# set x as a reactive function that adds 100 to input1
x <- reactive({as.numeric(input$text1)+100})
# set value of x to output object text1
output$text1 <- renderText({ x() })
# set value of x plus value of input object text2 to output object text1
output$text2 <- renderText({ x() + as.numeric(input$text2) })
})
  • functions/output objects in shinyServer()
    • output$oid1 <- renderPrint({input$id1}) = stores the user input value in field id1 and stores the rendered, printed text in the oid1 variable of the output object
      • renderPrint({expression}) = reactive function to render the specified expression
      • {} is used to ensure the value is an expression
      • oid1 = variable in the output object that stores the result from the subsequent command
    • output$sampleHist <- renderPlot({code}) = stores plot generated by code into sampleHist variable
      • renderPlot({code}) = renders a plot generated by the enclosed R code
    • output$sampleGVisPlot <- renderGvis({code}) = renders Google Visualization object

1.5 server.R Examples

  • basic example (from above)
# basic app with sliders and plot
library(shiny)
shinyServer(function(input, output) {
output$plot1 <- renderPlot({
set.seed(2016-05-25)
number_of_points <- input$numeric
minX <- input$sliderX[1]
maxX <- input$sliderX[2]
minY <- input$sliderY[1]
maxY <- input$sliderY[2]
dataX <- runif(number_of_points, minX, maxX)
dataY <- runif(number_of_points, minY, maxY)
xlab <- ifelse(input$show_xlab, "X Axis", "")
ylab <- ifelse(input$show_ylab, "Y Axis", "")
main <- ifelse(input$show_title, "Title", "")
plot(dataX, dataY, xlab = xlab, ylab = ylab, main = main,
xlim = c(-100, 100), ylim = c(-100, 100))
})
})
  • example with tabs (from above)
library(shiny)
shinyServer(function(input, output) {
output$out1 <- renderText(input$box1)
output$out2 <- renderText(input$box2)
output$out3 <- renderText(input$box3)
})
  • example with interactive graphics (from above)
library(shiny)
shinyServer(function(input, output) {
model <- reactive({
brushed_data <- brushedPoints(trees, input$brush1,
xvar = "Girth", yvar = "Volume")
if(nrow(brushed_data) < 2){
return(NULL)
}
lm(Volume ~ Girth, data = brushed_data)
})
output$slopeOut <- renderText({
if(is.null(model())){
"No Model Found"
} else {
model()[[1]][2]
}
})
output$intOut <- renderText({
if(is.null(model())){
"No Model Found"
} else {
model()[[1]][1]
}
})
output$plot1 <- renderPlot({
plot(trees$Girth, trees$Volume, xlab = "Girth",
ylab = "Volume", main = "Tree Measurements",
cex = 1.5, pch = 16, bty = "n")
if(!is.null(model())){
abline(model(), col = "blue", lwd = 2)
}
})
})
  • below is part of the server.R code for a project on Shiny that uses googleVis
# load libraries
library(shiny)
require(googleVis)
# begin shiny server
shinyServer(function(input, output) {
# define reactive parameters
pop<- reactive({sample(1:20, input$population, replace = TRUE)})
bootstrapSample<-reactive({sample(pop(),input$sampleSize*input$numSample,
replace = TRUE)})
popVar<- reactive({round(var(pop()),2)})
# print text through reactive funtion
output$biaVar <- renderText({
sample<- as.data.frame(matrix(bootstrapSample(), nrow = input$numSample,
ncol =input$sampleSize))
return(round(mean(rowSums((sample-rowMeans(sample))^2)/input$sampleSize), 2))
})
# google visualization histogram
output$popHist <- renderGvis({
popHist <- gvisHistogram(data.frame(pop()), options = list(
height = "300px",
legend = "{position: 'none'}", title = "Population Distribution",
subtitle = "samples randomly drawn (with replacement) from values 1 to 20",
histogram = "{ hideBucketItems: true, bucketSize: 2 }",
hAxis = "{ title: 'Values', maxAlternation: 1, showTextEvery: 1}",
vAxis = "{ title: 'Frequency'}"
))
return(popHist)
})
})

1.6 Distributing Shiny Application

  • running code locally = running local server and browser routing through local host
    • quickest way = send application directory
    • possible to create R package and create a wrapper that calls runApp (requires R knowledge)
  • you can post your app to GitHub and instruct the user to use the runGist() or runGitHub() function to launch your app
  • another option is to run shiny server (link)
  • Using shinyapps.io allows users to interact with your app through a web browser without needing to have R or Shiny installed

1.7 Debugging

  • runApp(display.mode = 'showcase') = highlights execution while running a shiny application
  • cat = can be used to display output to stdout/R console
  • browser() = interrupts execution (tutorial)

2 manipulate Package

# load data and manipulate package
library(UsingR)
library(manipulate)
# plotting function
myHist <- function(mu){
# histogram
hist(galton$child,col="blue",breaks=100)
# vertical line to highlight the mean
lines(c(mu, mu), c(0, 150),col="red",lwd=5)
# calculate mean squared error
mse <- mean((galton$child - mu)^2)
# updates the mean value as the mean is changed by the user
text(63, 150, paste("mu = ", mu))
# updates the mean squared error value as the mean is changed by the user
text(63, 140, paste("MSE = ", round(mse, 2)))
}
# creates a slider to vary the mean for the histogram
manipulate(myHist(mu), mu = slider(62, 74, step = 0.5))

3 Shiny Gadgets

library(shiny)
library(miniUI)
myFirstGadget <- function() {
ui <- miniPage(
gadgetTitleBar("My First Gadget")
)
server <- function(input, output, session) {
# The Done button closes the app
observeEvent(input$done, {
stopApp()
})
}
runGadget(ui, server)
}
myFirstGadget()
library(shiny)
library(miniUI)
multiplyNumbers <- function(numbers1, numbers2) {
ui <- miniPage(
gadgetTitleBar("Multiply Two Numbers"),
miniContentPanel(
selectInput("num1", "First Number", choices=numbers1),
selectInput("num2", "Second Number", choices=numbers2)
)
)
server <- function(input, output, session) {
observeEvent(input$done, {
num1 <- as.numeric(input$num1)
num2 <- as.numeric(input$num2)
stopApp(num1 * num2)
})
}
runGadget(ui, server)
}
multiplyNumbers(1:10,1:10)
library(shiny)
library(miniUI)
pickTrees <- function() {
ui <- miniPage(
gadgetTitleBar("Select Points by Dragging your Mouse"),
miniContentPanel(
plotOutput("plot", height = "100%", brush = "brush")
)
)
server <- function(input, output, session) {
output$plot <- renderPlot({
plot(trees$Girth, trees$Volume, main = "Trees!",
xlab = "Girth", ylab = "Volume")
})
observeEvent(input$done, {
stopApp(brushedPoints(trees, input$brush,
xvar = "Girth", yvar = "Volume"))
})
}
runGadget(ui, server)
}
pickTrees()

4 rCharts

# load rCharts package
require(rCharts); library(datasets); library(knitr)
# create dataframe with HairEyeColor data
haireye = as.data.frame(HairEyeColor)
# create a nPlot object
n1 <- nPlot(Freq ~ Hair, group = 'Eye', type = 'multiBarChart',
data = subset(haireye, Sex == 'Male'))
# save the nPlot object to a html page
n1$show("inline", include_assets = TRUE, cdn = F)

5 ggvis package

# for HTML version
library(ggvis)
mtcars %>%
ggvis(~mpg, ~wt, fill = ~ as.factor(am)) %>%
layer_points() %>%
layer_smooths() %>%
set_options(renderer = "canvas")
# for pdf version
library(ggvis)
mtcars %>%
ggvis(~mpg, ~wt, fill = ~ as.factor(am)) %>%
layer_points() %>%
layer_smooths()

6 GoogleVis API

6.1 Example (line chart)

# load googleVis package
suppressPackageStartupMessages(library(googleVis))
# set gvis.plot options to only return the chart
op <- options(gvis.plot.tag='chart')
# create initial data with x variable as "label" and y variable as "var1/var2"
df <- data.frame(label=c("US", "GB", "BR"), val1=c(1,3,4), val2=c(23,12,32))
# set up a gvisLineChart with x and y
Line <- gvisLineChart(df, xvar="label", yvar=c("val1","val2"),
# set options for the graph (list) - title and location of legend
options=list(title="Hello World", legend="bottom",
# set title text style
titleTextStyle="{color:'red', fontSize:18}",
# set vertical gridlines
vAxis="{gridlines:{color:'red', count:3}}",
# set horizontal axis title and style
hAxis="{title:'My Label', titleTextStyle:{color:'blue'}}",
# set plotting style of the data
series="[{color:'green', targetAxisIndex: 0},
{color: 'blue',targetAxisIndex:1}]",
# set vertical axis labels and formats
vAxes="[{title:'Value 1 (%)', format:'##,######%'},
{title:'Value 2 (\U00A3)'}]",
# set line plot to be smoothed and set width and height of the plot
curveType="function", width=500, height=300
))
# print the chart in JavaScript
plot(Line)

6.2 Example (merging graphs)

G <- gvisGeoChart(Exports, "Country", "Profit",options=list(width=200, height=100))
T1 <- gvisTable(Exports,options=list(width=200, height=270))
M <- gvisMotionChart(Fruits, "Fruit", "Year", options=list(width=400, height=370))
GT <- gvisMerge(G,T1, horizontal=FALSE)
GTM <- gvisMerge(GT, M, horizontal=TRUE,tableOptions="bgcolor=\"#CCCCCC\" cellspacing=10")
plot(GTM)
  • Note: the motion chart only displays when it is hosted on a server or a trusted Macromedia source, see googlVis vignette for more details

8 Structure of a Data Analysis Report

9 R Markdown

9.1 YAML

  • The beginning of an R Markdown file looks like this:
---
title: "Air Quality"
author: "JHU"
date: "May 17, 2016"
output: html_document
---
  • You can change the type of document generated by changing the output line in the YAML header, or by selecting an output from the Knit button’s pull-down menu.
  • HTML: two options with different looks
    • output: ioslides_presentation
    • output: slidy_presentation
  • PDF: output: beamer_presentation
    • To knit a PDF slideshow, you will need to install LaTeX on your computer
    • LaTeX is a typesetting system that is needed to convert R Markdown into formatted text for PDFs
  • Note: You can specify multiple outputs at the beginning of the R Markdown file if you will need to generate multiple filetypes

9.2 Syntax

  • Title a slide using two # signs: ## Insert Title Here
  • To make a slide without a title, use three asterisks: ***
  • You can add subheadings with more # signs: ### Subheading or #### Smaller Subheading
  • Adding Text:
    • Add bullet points to a slide using a hyphen followed by a space: - bullet point
    • Add sub-points using four spaces and a plus sign: + sub-point
    • Add an ordered list by typing the number/letter: 1. first point or a) sub-sub-point
    • Add bullet points that appear one by one (on click) with: >- iterated bullet point

9.3 Formatting Text

Text Code in R Markdown
plain text plain text
italics *italics*
bold **bold**
link [link](http://www.jhsph.edu)
verbatim code \code here\

9.4 Embedding R Code

  • This is a chunk of R code in R Markdown that gets run, and both the input and output are displayed:
      ```{r}
      head(airquality)
      ```
      
  • To hide the input code, set echo=FALSE in the chunk options (This can be useful for showing plots)
      ```{r, echo=FALSE}
      head(airquality)
      ```
      
  • To show the input code only, set eval=FALSE in the chunk options
      ```{r, eval=FALSE}
      head(airquality)
      ```
      
  • To run the code without showing input or output, use include=FALSE in the chunk options
      ```{r, include=FALSE}
      head(airquality)
      ```
      
  • By default R code produces two # signs in front of the output, use comment="" in the chunk options to get rid of it
      ```{r, comment=""}
      head(airquality)
      ```
      

9.5 Sharing R Markdown Products

  • 3 ways for sharing the HTML files that were produced from R Markdown documents

10 Leaflet

library(leaflet)
my_map <- leaflet() %>%
# use the following instead of addTiles()
addProviderTiles(providers$OpenStreetMap)
# addTiles()
my_map
my_map <- leaflet() %>%
addTiles() %>%
addMarkers(lat=39.2980803, lng=-76.5898801,
popup="Jeff Leek's Office")
my_map
set.seed(2016-04-25)
df <- data.frame(lat = runif(20, min = 39.2, max = 39.3),
lng = runif(20, min = -76.6, max = -76.5))
df %>%
leaflet() %>%
addTiles() %>%
addMarkers()
hopkinsIcon <- makeIcon(
iconUrl = "http://brand.jhu.edu/content/uploads/2014/06/university.shield.small_.blue_.png",
iconWidth = 31*215/230, iconHeight = 31,
iconAnchorX = 31*215/230/2, iconAnchorY = 16
)
hopkinsLatLong <- data.frame(
lat = c(39.2973166, 39.3288851, 39.2906617, 39.2970681, 39.2824806),
lng = c(-76.5929798, -76.6206598, -76.5469683, -76.6150537, -76.6016766))
hopkinsSites <- c(
"<a href='http://www.jhsph.edu/'>East Baltimore Campus</a>",
"<a href='https://apply.jhu.edu/visit/homewood/'>Homewood Campus</a>",
"<a href='http://www.hopkinsmedicine.org/johns_hopkins_bayview/'>Bayview Medical Center</a>",
"<a href='http://www.peabody.jhu.edu/'>Peabody Institute</a>",
"<a href='http://carey.jhu.edu/'>Carey Business School</a>"
)
hopkinsLatLong %>%
leaflet() %>%
addTiles() %>%
addMarkers(icon = hopkinsIcon, popup = hopkinsSites)
df <- data.frame(lat = runif(500, min = 39.25, max = 39.35),
lng = runif(500, min = -76.65, max = -76.55))
df %>%
leaflet() %>%
addTiles() %>%
addMarkers(clusterOptions = markerClusterOptions())
df <- data.frame(lat = runif(20, min = 39.25, max = 39.35),
lng = runif(20, min = -76.65, max = -76.55))
df %>%
leaflet() %>%
addTiles() %>%
addCircleMarkers()
md_cities <- data.frame(name = c("Baltimore", "Frederick", "Rockville", "Gaithersburg",
"Bowie", "Hagerstown", "Annapolis", "College Park", "Salisbury", "Laurel"),
pop = c(619493, 66169, 62334, 61045, 55232,
39890, 38880, 30587, 30484, 25346),
lat = c(39.2920592, 39.4143921, 39.0840, 39.1434,
39.0068, 39.6418, 38.9784, 38.9897, 38.3607, 39.0993),
lng = c(-76.6077852, -77.4204875, -77.1528, -77.2014,
-76.7791, -77.7200, -76.4922, -76.9378, -75.5994, -76.8483))
md_cities %>%
leaflet() %>%
addTiles() %>%
addCircles(weight = 4, radius = sqrt(md_cities$pop) * 30)
leaflet() %>%
addTiles() %>%
addRectangles(lat1 = 37.3858, lng1 = -122.0595,
lat2 = 37.3890, lng2 = -122.0625)
df <- data.frame(lat = runif(20, min = 39.25, max = 39.35),
lng = runif(20, min = -76.65, max = -76.55),
col = sample(c("red", "blue", "green"), 20, replace = TRUE),
stringsAsFactors = FALSE)
df %>%
leaflet() %>%
addTiles() %>%
addCircleMarkers(color = df$col) %>%
addLegend(labels = LETTERS[1:3], colors = c("blue", "red", "green"))

11 Slidify

11.1 YAML (YAML Ain’t Markup Language/Yet Another Markup Language)

  • used to specify options for the R Markdown/slidify at the beginning of the file
  • format: field : value # comment
    • title = title of document
    • subtitle = subtitle of document
    • author = author of document
    • job = occupation of author (can be left blank)
    • framework = controls formatting, usually the name of a library is used (i.e. io2012)
    • highlighter = controls effects for presentation (i.e highlight.js)
    • hitheme = specifies theme of code (i.e. tomorrow)
    • widgets = loads additional libraries to display LaTeX math equations(mathjax), quiz-styles components (quiz), and additional style (bootstrap = Twitter-created style)
      • for math expressions, the code should be enclosed in $expresion$ for inline expressions, and $$expression$$ for block equations
    • mode = selfcontained/standalone/draft = depending whether the presentation will be given with Internet access or not
      • standalone = all the JavaScript libraries will be save locally so that the presentation can be executed without Internet access
      • selfcontained = load all JavaScript library at time of presentation
    • logo = displays a logo in title slide
    • url = specify path to assets/other folders that are used in the presentation
      • Note: ../ signifies the parent directory
  • Example
---
title : Slidify
subtitle : Data meets presentation
author : Jeffrey Leek, Assistant Professor of Biostatistics
job : Johns Hopkins Bloomberg School of Public Health
logo : bloomberg_shield.png
framework : io2012 # {io2012, html5slides, shower, dzslides, ...}
highlighter : highlight.js # {highlight.js, prettify, highlight}
hitheme : tomorrow #
url:
lib: ../../libraries
assets: ../../assets
widgets : [mathjax] # {mathjax, quiz, bootstrap}
mode : selfcontained # {standalone, draft}
---

11.2 Slides

  • ## = signifies the title of the slide \(\rightarrow\) equivalent of h1 element in HTML
  • --- = marks the end of a slide
  • .class #id = assigns class and id attributes (CSS) to the slide and can be used to customize the style of the page
  • Note: make sure to leave space between each component of the slidify document (title, code, text, etc) to avoid errors
  • advanced HTML can be added directly to the index.Rmd file and most of the time it should function correctly
  • interactive element (quiz questions, rCharts, shiny apps) can be embedded into slidify documents (demos)
    • quiz elements
      • --- &radio before slide content for multiple choice (make sure quiz is included in widgets)
      • ## = signifies title of questions
      • the question can be type in plain text format
      • the multiple choice options are listed by number (1. a, 2. b, etc.)
        • wrap the correct answer in underscores (2. _b_)
      • *** .hint = denotes the hint that will be displayed when the user clicks on Show Hint button
      • *** .explanation = denotes the explanation that will be displayed when the user clicks on Show Answer button
      • a page like the one below will be generated when processed with slidify
--- &radio
# Question 1
What is 1 + 1?
1. 1
2. _2_
3. 3
4. 4
*** .hint
This is a hint
*** .explanation
This is an explanation

  • knit HTML button can be used to generate previews for the presentation as well

11.3 Publishing

  • first, you will need to create a new repository on GitHub
  • publish_github("user", "repo") can be used to publish the slidify document on to your on-line repo

12 RStudio Presentation

12.1 Creating Presentation

  • file \(\rightarrow\) New File \(\rightarrow\) R Presentation (alt-f + f + p)
  • class: classname = specify slide-specific control from CSS
  • css: file.css = can be used to import an external CSS file
    • alternatively, a css file that has the same name as the presentation will be automatically loaded
  • knowledge of CSS/HTML/JavaScript useful to customize presentation more granularly
    • Note: though the end HTML file can be edited directly, it should be used as a last resort as it defeats the purpose of reproducible presentations
  • clicking on Preview button brings up Presentation viewer in RStudio
    • navigation controls (left and right arrows) are located in right bottom corner
    • the Notepad icon on the menu bar above displays the section of code that corresponds with the current slide in the main window
    • the More button has four options
      • “Clear Knitr Cache” = clears cache for the generated presentation previews
      • “View in Browser” = creates temporary HTML file and opens in default web browser (does not create a local file)
      • “Save as Web Page” = creates a copy of the presentation as a web page
      • “Publish to RPubs” = publishes presentation on RPubs
    • the Refresh button refreshes the page
    • the Zoom button opens a new window to display the presentation
  • transitions between slides
    • just after the beginning of each slide, the transition property (similar to YAML) can be specified to control the transition between the previous and current slides
    • transition: linear = creates 2D linear transition (html5) between slides
    • transition: rotate = creates 3D rotating transition (html5) between slides
    • more transition options are found here
  • hierarchical organization
    • attribute type can be added to specify the appearance of the slide (“slide type”)
    • type: section and type: sub-section = distinct background and font colors, slightly larger heading text, appear at a different indent level within the slide navigation menu
    • type: prompt and type: alert = distinct background color to communicate to viewers that the slide has different intent
  • columns
    • simply place *** in between two sections of content on a slide to separate it into two columns
    • left: 70% can be used to specify the proportions of each column
    • right: 30% works similarly
  • change slide font (guide)
    • font-family: fontname = changes the font of slide (specified in the same way as HTML)
    • font-import: http://fonts.googleapis.com/css?family=Risque = imports font
      • Note: fonts must be present on the system for presentation (or have Internet), or default fonts will be used
    • Note: CSS selectors for class and IDs must be preceded by .reveal to work (.reveal section del applies to any text enclosed by ~~text~~)

13 Slidify vs RStudio Presenter

14 R Package

14.1 R Package Components

  • directory with name of R package = created as first step
  • DESCRIPTION file = metadata/information about package
  • R code = code should be in R/ sub-directory
  • Documentation = file should be in man/ sub-directory
  • NAMESPACE = optional but common and best practice
  • full requirements documented in Writing R Extensions

14.2 DESCRIPTION file

  • Package = name of package (e.g. library(name) to load the package)
  • Title = full name of package
  • description = longer description of package in one or two sentences
  • Version = version number (usually M.m-p format, “majorNumber.minorNumber-patchLevel”)
  • Author = Name of the original author(s)
  • Maintainer = name + email of person (maintainer) who fixes problems
  • License = license for the source code, describes the term that the source code is released under
    • common licenses include GNU/BSD/MIT
    • typically a standard open source license is used
  • optional fields
    • Depends = R packages that your package depends on
    • Suggests = optional R packages that users may want to have installed
    • Date = release date in YYYY-MM-DD format
    • URL = package home page/link to repository
    • Other = fields can be added (generally ignored by R)
  • Example: gpclib
    • Package: gpclib
    • Title: General Polygon Clipping Library for R
    • Description: General polygon clipping routines for R based on Alan Murta’s C library
    • Version: 1.5-5
    • Author: Roger D. Peng rpeng@jhsph.edu with contributions from Duncan Murdoch and Barry Rowlingson; GPC library by Alan Murta
    • Maintainer: Roger D. Peng rpeng@jhsph.edu
    • License: file LICENSE
    • Depends: R (>= 2.14.0), methods
    • Imports: graphics
    • Date: 2013-04-01
    • URL: http://www.cs.man.ac.uk/~toby/gpc/, http://github.com/rdpeng/gpclib

14.3 R Code

  • copy R code to R/ sub-directory
  • can be any number of files
  • separate out files to logical groups (read/fit models)
  • all code should be included here and not anywhere else in the package

14.4 NAMESPACE file

  • effectively an API for the package
  • indicates which functions are exported \(\rightarrow\) public functions that users have access to and can use
    • functions not exported cannot be called directly by the user
    • hides the implementation details from the users (clean package interface)
  • lists all dependencies on other packages/indicate what functions you imported from other packages
    • allows for your package to use other packages without making them visible to the user
    • importing a function loads the package but does not attach it to the search list
  • key directives
    • export("<function>") = export a function
    • import("<package>") = import a package
    • importFrom("<package>", "<function>") = import specific function from a package
    • exportClasses("<class>") = indicate the new types of S4 (4th version of S) classes created with the package (objects of the specified class can be created)
    • exportMethods("<generic>") = methods that can operate on the new class objects
    • Note: though they look like R functions, the above directives are not functions that users can use freely
  • Example: NAMESPACE file from gpclib package
# read.polyfile/write.polyfile are functions available to user
export("read.polyfile", "write.polyfile")
# import plot function from graphics package
importFrom(graphics, plot)
# gpc.poly/gpc.poly.nohole classes can be created by the user
exportClasses("gpc.poly", "gpc.poly.nohole")
# the listed methods can be applied to the gpc.poly/gpc.poly.nohole classes
exportMethods("show", "get.bbox", "plot", "intersect", "union", "setdiff",
"[", "append.poly", "scale.poly", "area.poly", "get.pts",
"coerce", "tristrip", "triangulate")

14.5 Documentation

  • documentation files (.Rd) should be placed in the man/ sub-directory
  • written in specific markup language
  • documentation files are required for every exported function available to the user (serves to limit the number of exported functions)
  • concepts/package/datasets overview can also be documented

  • components
    • \name{} = name of function
    • \alias{} = anything listed as alias will bring up the help file (?line is the same as ?residuals.tukeyline)
      • multiple aliases possible
    • \title{} = full title of the function
    • \description{} = full description of the purpose of function
    • \usage{} = format/syntax of function
    • \arguments{} = explanation of the arguments in the syntax of function
    • \details{} = notes/details about limitation/features of the function
    • \value{} = specifies what object is returned
    • \reference{} = references for the function (paper/book from which the method is created)
  • Help File Example: line function

\name{line}
\alias{line}
\alias{residuals.tukeyline}
\title{Robust Line Fitting}
\description{
Fit a line robustly as recommended in \emph{Exploratory Data Analysis}.
}
\usage{
line(x, y)
}
\arguments{
\item{x, y}{the arguments can be any way of specifying x-y pairs. See
\code{\link{xy.coords}}.}
}
\details{
Cases with missing values are omitted.
Long vectors are not supported.
}
\value{
An object of class \code{"tukeyline"}.
Methods are available for the generic functions \code{coef},
\code{residuals}, \code{fitted}, and \code{print}.
}
\references{
Tukey, J. W. (1977).
\emph{Exploratory Data Analysis},
Reading Massachusetts: Addison-Wesley.
}

14.6 Building/Checking Package

  • R CMD build = command-line program that creates a package archive file (format = .tar.gz)
  • R CMD check = command-line program that runs a battery of tests on the package to ensure structure is consistent/all components are present/export and import are appropriately specified
  • R CMD build/R CMD check can be run from the command-line using terminal/command-shell applications
  • alternatively, they can be run from R using the system() function
    • system("R CMD build newpackage")
    • system("R CMD check newpackage")
  • the package must pass all tests to be put on CRAN
    • documentation exists for all exported function
    • code can be loaded without any major coding problems/errors
    • contains license
    • ensure examples in documentation can be executed
    • check documentation of arguments matches argument in the code
  • package.skeleton() function in the utils package = creates a “skeleton” R package
    • automatically creates directory structure (R/, man/), DESCRIPTION file, NAMESPACE file, documentation files
    • if there are any visible/stored functions in the current workspace, their code will be written as R code files in the R/ directory
    • documentation stubs are created in man/ directory
    • the rest of the content can then be modified and added
  • alternatively, you can click on the menu on the top right hand corner of RStudio: Project \(\rightarrow\) New Project \(\rightarrow\) New Directory \(\rightarrow\) R Package \(\rightarrow\) fill in package names and details \(\rightarrow\) automatically generate structure/skeleton of a new R package

14.7 Checklist for Creating Package

  • create a new directory with R/ and man/ sub-directories (or just use package.skeleton())
  • write a DESCRIPTION file
  • copy R code into the R/ sub-directory
  • write documentation files in man/ sub-directory
  • write a NAMESPACE file with exports/imports
  • build and check

14.8 Example: topten function

  • when creating a package, generate skeleton by clicking on Project \(\rightarrow\) New Project \(\rightarrow\) New Directory \(\rightarrow\) R Package \(\rightarrow\) fill in package names and details
  • write the code first in a .R script and add documentation directly to the script
    • Roxygen2 package will be leveraged to extract and format the documentation from R script automatically
  • Roxygen2 syntax
    • #' = denotes the beginning of documentation
      • R will automatically add #' on the subsequent lines as you type or complete sections
    • title should be on the first line (relatively concise, a few words)
      • press ENTER after you are finished and R will automatically insert an empty line and move the cursor to the next section
    • description/summary should begin on the third line (one/two sentences)
      • press ENTER after you are finished and R will automatically insert an empty line and move the cursor to the next section
    • @param x definition = format of the documentation for the arguments
      • x = argument name (formatted in code format when processed to differentiate from definition)
      • definiton = explanation of the what x represents
    • @author = author of the function
    • @details = detailed description of the function and its purpose
    • @seealso = links to relevant functions used in creating the current function that may be of interest to the user
    • @import package function = imports specific function from specified package
    • @export = denotes that this function is exported for public use
    • @return = specifies what is returned by the method
#' Building a Model with Top Ten Features
#'
#' This function develops a prediction algorithm based on the top 10 features
#' in 'x' that are most predictive of 'y'.
#'
#' @param x a n x p matrix of n observations and p predictors
#' @param y a vector of length n representing the response
#' @return a 'lm' object representing the linear model with the top 10 predictors
#' @author Roger Peng
#' @details
#' This function runs a univariate regression of y on each predictor in x and
#' calculates the p-value indicating the significance of the association. The
#' final set of 10 predictors is the taken from the 10 smallest p-values.
#' @seealso \code{lm}
#' @export
#' @importFrom stats lm
topten <- function(x, y) {
p <- ncol(x)
if(p < 10)
stop("there are less than 10 predictors")
pvalues <- numeric(p)
for(i in seq_len(p)) {
fit <- lm(y ~ x[, i])
summ <- summary(fit)
pvalues[i] <- summ$coefficients[2, 4]
}
ord <- order(pvalues)
ord <- ord[1:10]
x10 <- x[, ord]
fit <- lm(y ~ x10)
coef(fit)
}
#' Prediction with Top Ten Features
#'
#' This function takes a set coefficients produced by the \code{topten}
#' function and makes a prediction for each of the values provided in the
#' input 'X' matrix.
#'
#' @param X a n x 10 matrix containing n observations
#' @param b a vector of coefficients obtained from the \code{topten} function
#' @return a numeric vector containing the predicted values
#' @export
predict10 <- function(X, b) {
X <- cbind(1, X)
drop(X %*% b)
}

15 R Classes and Methods

15.1 Objected Oriented Programming in R

  • class = description of something or anobject (defines new data types/ideas)
    • can be defined using setClass() function in methods package
    • all objects in R have a class, which can be determined through the class() function
      • numeric = number data, can be vectors as well (series of numbers)
      • logical = TRUE, FALSE, NA
        • Note: NA is by default of logical class, however you can have numeric/character NA’s as results of operations
      • character = string of characters
      • lm = linear model class, output from a linear model
  • object = instances of a class
    • can be created using new()
  • method = function that operates on certain class of objects
    • also can be thought of as an implementation of a generic function for an object of particular class
    • can write new methods for an existing generic function OR create your own generics and associated methods
    • hence, methods extend generic functions to specify the behavior of generic functions on new classes
    • getS3method(<genericFunction>, <class>) = returns code for S3 method for a given class
      • some S3 methods can be called directly (i.e. mean.default)
      • but you should never call them, always use the generic
    • getMethod(<genericFunction>, <signature/class>) = returns code for S4 method for a given class
      • signature = a character vector indicating the classes of objects that are accepted by the method
      • S4 methods can not be called at all
  • generic function = R function that dispatches methods to perform a certain task (eg. plot, mean, predict, print)
    • performs different calculations depending on context
    • Note: generic functions themselves don’t perform any computation; typing the function name by itself (i.e. plot) will return the content of the function
    • S3 and S4 functions look different but are similar conceptually
    • methods("mean") = returns methods associated with S3 generic function
    • showMethods("show") = returns methods associated with S4 generic function
      • Note: show is equivalent of print, but generally not called directly as objects are auto-printed
  • Generic/method mechanism:
    • first argument of a generic function is an object of particular class
    1. generic function checks the class of object
    2. a search is done to see if there is an appropriate method for that class
    3. if there exists a method for that class, then that method is called on the object and we’re done
    4. if no method exists for that class, a search is done to see if there is a default method for the generic
    5. if default method exists, then the default method is called on object
    6. if no default method exists, then an error is thrown
  • if a data type does not exist in R that matches your needs, you can always defina a new class along with generics/methods that go with it
  • as new data types and concepts are created, classes/methods provide a way for you to develop an intuitive interface to those data/concepts for users

  • Note: ?Classes, ?Methods, ?setClass, ?setMethod, and ?setGeneric contains very helpful documentation

  • Example: S3 Class/Method

# S3 method: mean
mean
## function (x, ...) 
## UseMethod("mean")
## <bytecode: 0x55cf40144310>
## <environment: namespace:base>
# associated methods
methods("mean")
## [1] mean.Date     mean.default  mean.difftime mean.IDate*   mean.POSIXct 
## [6] mean.POSIXlt 
## see '?methods' for accessing help and source code
# code for mean (first 10 lines)
# note: no specific function got numeric class, so default function for "mean" is used
# look at the default method for the mean function by using the getS3method function
head(getS3method("mean", "default"), 10)
##                                                                       
## 1  function (x, trim = 0, na.rm = FALSE, ...)                         
## 2  {                                                                  
## 3      if (!is.numeric(x) && !is.complex(x) && !is.logical(x)) {      
## 4          warning("argument is not numeric or logical: returning NA")
## 5          return(NA_real_)                                           
## 6      }                                                              
## 7      if (na.rm)                                                     
## 8          x <- x[!is.na(x)]                                          
## 9      if (!is.numeric(trim) || length(trim) != 1L)                   
## 10         stop("'trim' must be numeric of length one")
  • Example: S3 Class/Method for dataframes
    • classes like data.frame where each column can be an object of a different class
    • we sapply over the columns and call the mean function
    • In each column, mean chechs the class of the object and dispatches the appropriate method
    • we have a numeric column and an integer column; mean calls the default method for both
set.seed(3)
df <- data.frame(x = rnorm(100), y = 1:100)
sapply(df, mean)
  • Example: S3 Class/Method for plot
    • plot function is generic and its behavior depends on the object being plotted
par(mfrow = c(1,2))
set.seed(10)
x <- rnorm(100)
plot(x)
# different from above
set.seed(10)
x <- rnorm(100)
x <- as.ts(x) # Convert to a time series object
plot(x)

  • Example: S4 Class/Method
# S4 method: show
show
## standardGeneric for "show" defined from package "methods"
## 
## function (object) 
## standardGeneric("show")
## <bytecode: 0x55cf3bccb9e0>
## <environment: 0x55cf3a90cc80>
## Methods may be defined for arguments: object
## Use  showMethods("show")  for currently available ones.
## (This generic function excludes non-simple inheritance; see ?setIs)
# associated methods
showMethods("show")
## Function: show (package methods)
## object="ANY"
## object="C++Class"
## object="C++Function"
## object="C++Object"
## object="classGeneratorFunction"
## object="classRepresentation"
## object="color"
## object="envRefClass"
## object="externalRefMethod"
## object="function"
##     (inherited from: object="ANY")
## object="genericFunction"
## object="genericFunctionWithTrace"
## object="MethodDefinition"
## object="MethodDefinitionWithTrace"
## object="MethodSelectionReport"
## object="MethodWithNext"
## object="MethodWithNextWithTrace"
## object="Module"
## object="namedList"
## object="ObjectsWithPackage"
## object="oldClass"
## object="refClassRepresentation"
## object="refMethodDef"
## object="refObjectGenerator"
## object="signature"
## object="sourceEnvironment"
## object="standardGeneric"
##     (inherited from: object="genericFunction")
## object="traceable"

15.2 Creating a New Class/Methods

  • reason for creating new classes/data type (not necessarily unknown to the world, but just unknown to R)
    • powerful way to extend the functionality of R
    • represent new types of data (e.g. gene expression, space-time, hierarchical, sparse matrices)
    • new concepts/ideas that haven’t been thought of yet (e.g. a fitted point process model, mixed-effects model, a sparse matrix)
    • abstract/hide implementation details from the user
  • Basically there are two ways that you can extend the R system via classes/methods:
    • Write a method for a new class but for an existing generic function (i.e. like print)
    • Write new generic functions and new methods for those generics
  • classes = define new data types
  • methods = extend generic functions to specify the behavior of generic functions on new classes

  • setClass() = function to create new class
    • at minimum, name of class needs to be specified
    • slots or attributes can also be specified
      • think of a class as a list, so slots are elements of that list
  • setMethod() = define methods for class
    • @ is used to access the slots/attributes of the class
    • for setMethod you need to specify a generic function (eg. plot) and a signature
  • showClass() = displays definition/information about class
  • when drafting new class, new methods for print  show, summary, and plot should be written
  • Note: creating classes are not something to be done on the console and are much better suited for a script
  • Example
    • create ploygon class with set of (x, y) coordinates with setClass()
    • define a new plot function by extending existing plot function with setMethod()
# load methods library
library(methods)
# create polygon class with x and y coordinates as slots
setClass("polygon", representation(x = "numeric", y = "numeric"))
# create plot method for ploygon class (ploygon = signature in this case)
setMethod("plot", "polygon",
# x is the polygon object, y is not needed in the function
function(x, y, ...) {
# notice that the slots of the polygon are accessed with the @ operator
plot(x@x, x@y, type = "n", ...)
# plots lines between all (x, y) pairs
# x@x[1] is added at the end because we need
# to connect the last point of polygon to the first
xp <- c(x@x, x@x[1])
yp <- c(x@y, x@y[1])
lines(xp, yp)
})
## [1] "plot"
# print polygon method
# notice that the signature for class polygon is listed
# the ANY is the default method and it is what is called what no other signature matches
showMethods("plot")
## Function: plot (package graphics)
## x="ANY"
## x="color"
## x="polygon"
# create a object of the newly created polygon class and plot
p <- new("polygon", x = c(1,2,3,4), y = c(1,2.5,3,1))
plot(p)

16 Swirl

16.1 Creating lessons

Create a lesson using the Shiny lesson authoring app

swirlify("Lesson 1", "My First Course")

Create a lesson using the R console

  • To start a new lesson from the R console, set your working directory, and then use the new_lesson() function to create the course
new_lesson("My First Lesson", "My First Course")
  • it will create a file and folder structure like this in your working directory:
My_First_Course
    - My_First_Lesson
        - lesson.yaml
        - initLesson.R
        - dependson.txt
        - customTests.R
  • Several files were created inside of ./My_First_Course/My_First_Lesson:
    • lesson.yaml is where you will write all of the questions for this lesson
    • initLesson.R is an R script that is run before the lesson starts which is usually used to load data or set up environmental variables.
    • dependson.txt is the list of R packages your lesson will require. Swirl will install these packages if the user doesn’t already have them installed.
    • customTests.R is where you can write your own tests for student’s answers.
  • Every lesson must contain one lesson.yaml file which structures the text that the student will see inside the R console while they are using swirl.
    • The lesson.yaml file contains a sequence of questions that students will be prompted with
  • The first question in every lesson.yaml is always the meta question which contains general information about the course. Below is an example of the meta question:
- Class: meta
  Course: My Course
  Lesson: My Lesson
  Author: Dr. Jennifer Bryan
  Type: Standard
  Organization: The University of British Columbia
  Version: 2.5
  • Lessons are sequences of questions that have the following general structure:
    • Each question is demarcated with a hyphen.
    • Every question starts with a Class that specifies that question’s behavior inside of swirl.
    • What follows the class is a set of key-value pairs that will be used to render the question when a student is using swirl.
    • The example below shows the high-level structure for two questions.
- Class: [type of question]
  Key1: [value1]
  Key2: [value2]

- Class: [type of question]
  Key1: [value1]
  Key2: [value2]
...
  • Message questions display a string of text in the R console for the student to read. Once the student presses enter, swirl will move on to the next question.
    • Add a message question using wq_message()
- Class: text
  Output: Welcome to my first swirl course!
  • The student will see the following in the R console:
| Welcome to my first swirl course!

...
  • Command questions prompt the student to type an expression into the R console
    • The CorrectAnswer is entered into the console if the student uses the skip() function
    • The Hint is displayed to the student if they don’t get the question right
    • The AnswerTests determine whether or not the student answered the question correctly
    • Add a message question using wq_command().
- Class: cmd_question
  Output: Add 2 and 2 together using the addition operator.
  CorrectAnswer: 2 + 2
  AnswerTests: omnitest(correctExpr='2 + 2')
  Hint: Just type 2 + 2.
  • The student will see the following in the R console:
| Add 2 and 2 together using the addition operator.

>
  • Multiple choice questions present a selection of options to the student
    • These options are presented in a different order every time the question is seen.
    • The AnswerChoices should be a semicolon separated string of choices that the student will have to choose from.
    • Add a message question using wq_multiple().
- Class: mult_question
  Output: What is the capital of Canada?
  AnswerChoices: Toronto;Montreal;Ottawa;Vancouver
  CorrectAnswer: Ottawa
  AnswerTests: omnitest(correctVal='Ottawa')
  Hint: This city contains the Rideau Canal.
  • The student will see the following in the R console:
| What is the capital of Canada?

1: Toronto
2: Montreal
3: Ottawa
4: Vancouver
  • Other Question Types:
  • Handy functions:
    • test_lesson() runs basic tests on all questions in the current lesson.
    • demo_lesson() jumps right in to the current swirl lesson without needing to navigate swirl’s menus
    • get_current_lesson() prints the current lesson and course that you are working on to the console
  • Example: YAML file
- Class: meta
  Course: My First Course
  Lesson: Lesson 2
  Author: your name goes here
  Type: Standard
  Organization: your organization's name goes here
  Version: 2.4.3


- Class: mult_question
  Output: Which of these shapes has four sides?
  AnswerChoices: Square;Circle;Hexagon
  CorrectAnswer: Square
  AnswerTests: omnitest(correctVal= 'Square')
  Hint: You should  know this!

- Class: figure
  Output: This is a simple graph.
  Figure: fig1.R
  FigureType: new

- Class: figure
  Output: I added a line!
  Figure: fig2.R
  FigureType: add

16.2 Organizing Lessons

  • This is the structure of a course with two lessons:
My_First_Course
    - My_First_Lesson
        - lesson.yaml
        - initLesson.R
        - dependson.txt
        - customTests.R
    - My_Second_Lesson
        - lesson.yaml
        - initLesson.R
        - dependson.txt
        - customTests.R
  • By default each folder in My_First_Course will be displayed to the student as a lesson they can select
  • If you want to explicitly specify the order in which lessons are displayed you will need to add a MANIFEST file to your course.
    • You can do this with the add_to_manifest() function, which will add the lesson you are currently working on to the MANIFEST
    • You can also edit the MANIFEST yourself in a text editor.
    • The (abridged) MANIFEST file below belongs to Team swirl’s R Programming course:
Basic_Building_Blocks
Workspace_and_Files
Sequences_of_Numbers
Vectors
Missing_Values
Subsetting_Vectors
Matrices_and_Data_Frames

16.3 Sharing Your Course

  • swirlify makes sharing a swirl course easy
  • We recommend three different methods for sharing a swirl course.

1 Sharing Your Course as a File

  • We’ve developed the .swc file type so that you can share your course as a single file
  • Creating an .swc file for your course is easy:
    1. Set any lesson in the course you want to share as the current lesson using set_lesson()
    2. Create an .swc file using the pack_course() function
      • Your .swc file will appear in the same directory as the directory that contains the course folder
      • You also have the option to export the .swc file to another directory by specifying the export_path argument.
  • You can now share your .swc file like you would any other file (through email, file sharing services, etc).
  • Students can install your course from the .swc file by downloading the file and then using the install_course() function in swirl, which will prompt them to interactively select the file they downloaded.

2 Sharing Your Course on GitHub

  • Developing your course on GitHub provides the added benefit that your course will be instantly ready to distribute.
  • Students can install your course from swirl using the install_course_github() function
  • Make sure that your course directory is the root folder of your git repository. For examples of courses that have been shared on GitHub you can browse some of the courses on the Swirl Course Network

3 Sharing Your Course on The Swirl Course Network

  • The goal of the Swirl Course Network is to list and organize all publicly available swirl courses
    • Visit the homepage of the SCN for more information.
  • After adding your course to the SCN students will be able to install your course using install_course("[Name of Your Course]")
  • In order to add your course to the SCN:
    1. Create an .swc file for your course.
    2. Fork https://github.com/swirldev/scn on GitHub.
    3. Add the .swc file to your fork.
    4. Add an Rmd file to your fork like this one.
      • You can include a description of your course, authors, a course website, and how to install your course.
    5. Run rmarkdown::render_site() when your current directory is set to your fork.
    6. Add, commit, and push your changes to GitHub, then send us a Pull Request.